﻿using AutoPex.Core.Extensions;
using Microsoft.Cci;
using Microsoft.Cci.MutableCodeModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Diagnostics;

namespace AutoPex.Core
{
	public sealed class AssemblyDiffer
	{
		private IMetadataHost host;

		public AssemblyDiffer()
			: base()
		{
			this.host = new HostEnvironment();
		}

		private IModule GetModuleFromFile(FileSystemInfo assemblyLocation)
		{
			return this.host.LoadUnitFrom(assemblyLocation.FullName) as IModule;
		}

		public ReadOnlyCollection<IMethodDefinition> GetMethodsToAnalyze(
			FileSystemInfo oldAssemblyLocation, FileSystemInfo newAssemblyLocation)
		{
			var oldModule = this.GetModuleFromFile(oldAssemblyLocation);
			var newModule = this.GetModuleFromFile(newAssemblyLocation);
			
			var methodsToAnalyze = new List<IMethodDefinition>();

			var oldMethods = (from type in oldModule.GetAllTypes()
									from method in type.Methods
									where (method.Visibility & TypeMemberVisibility.Public) == TypeMemberVisibility.Public
									select method).ToList();

			var newMethods = from type in newModule.GetAllTypes()
								  from method in type.Methods
								  where (method.Visibility & TypeMemberVisibility.Public) == TypeMemberVisibility.Public
								  select method;

			foreach(var newMethod in newMethods)
			{
				var newMethodInOldMethods = oldMethods.Find((oldMethod) =>
				{
					return oldMethod.Name.Value == newMethod.Name.Value;
				});

				if(newMethodInOldMethods == null || newMethod.IsDifferentFrom(newMethodInOldMethods))
				{
					methodsToAnalyze.Add(newMethod);
				}
			}
			
			return methodsToAnalyze.AsReadOnly();
		}
	}
}
